import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;

import java.net.Socket;
import java.net.SocketException;
import java.sql.Date;
import java.util.List;


/**
 * This class deals manages the messages that are recieved from
 * the client and executes the appropriate query commands to
 * retreive and input data into and from the database.
 *
 * @author Joshua Harris
 * @version 1.0
 */
public class ServerMessageHandler implements Runnable {
    
	/** 
	 * the socket for the client 
	 */
    private Socket sock;
    
    /**
     * the Database connector.
     */
    private MyQuery query;

    /**
     * Creates a new ServerMessageHandler object.
     *
     * @param sock the socket that the handler will use
     */
    public ServerMessageHandler(final Socket sock) {
        this.sock = sock;
        query = new MyQuery();
    }

    /**
     * Runs the client handler
     */
    public void run() {
        BufferedReader  inStream;
        PrintWriter outStream;
        System.out.println("Connection from: "
            + sock.getInetAddress().getHostName()+ ":" + sock.getPort());

        boolean stillRunning = true;

        try {
            //note that we are using a text protocol since
            //are reading with a buffered reader (1 string line at a time)
        	inStream = new BufferedReader(new InputStreamReader(
                        sock.getInputStream()));
            outStream = new PrintWriter(sock.getOutputStream());
            outStream.flush();
            
            while (stillRunning) {
                String line = null;
                while((line = inStream.readLine()) == null);
                String result = handleMessage(line);
                System.err.println(sock.getPort() + ": Got server message");
                if (!"QUIT".equals(result)) {
                
                    outStream.println(result);
                    outStream.flush();
                } else {
                    inStream.close();
                    outStream.close();
                    sock.close();
                    stillRunning = false;
                    System.out.println(sock.getPort() + ": CONNECTION CLOSED");
                }
            }
        } catch (SocketException se) {
            System.err.println("CLIENT DISCONNECTED");
        } catch (IOException e) {
            System.err.println(
                "IOEXCEPTION: error setting up streams or socket");
        }
    }
    
    /**
     * This method takes the string read in from the socket stream
     * and decides what to do with it based on the protocol.
     *
     * @param line the input line to handle
     *
     * @return a String which is the server response to the message
     */
    private String handleMessage(final String line) {
        List<String> list = MessageEditor.parseMessage(line);
        String type = list.remove(0);
        
        if("LOGIN ".equals(type)){
        	return login(list);
        }else if("ADDUSER ".equals(type)){
        	addUser(list);
        }else if("LOADUSER ".equals(type)){
        	return loadUser(list);
        }else if("UPDATEUSER ".equals(type)){
        	updateUser(list);
        }else if("DELETEUSER ".equals(type)){
        	deleteUser(list);
        }else if("SEARCHUSER ".equals(type)){
        	return searchUser(list);
        }else if("ADDAPP ".equals(type)){
        	addApp(list);
        }else if("UPDATEAPP ".equals(type)){
        	updateApp(list);
        }else if("DELETEAPP ".equals(type)){
        	deleteApp(list);
        }else if("SEARCHAPPDATE ".equals(type)){
        	return searchAppDate(list);
        }else if("SEARCHAPPSSN ".equals(type)){
        	return searchAppSSN(list);
        }else if("QUIT ".equals(type)){
        	return "QUIT";
        }else{
        	/* DO SOMETHING */
        }
        
    	return null;
    }
    
    private String login(List<String> list){
    	String username = list.get(0);
    	String password = list.get(1);
    	int role = Integer.parseInt(list.get(2));
    	
    	String tmpStr = "";
    	tmpStr = Integer.toString(role);
    	
    	Login newLogin = new Login(username, password, tmpStr);
    	User user = newLogin.authenticate(); 
    	
    	if(user != null){
    		return MessageEditor.makeRLogin(user);
    	}else{
    		return null;
    	}
    }
    
    private void addUser(List<String> list){
    	User user = UserMessageEditor.getUser(list.get(0));
    	if(user != null){
    		query.addUser(user);
    	}
    }
    
    private String loadUser(List<String> list){
    	int ssn = Integer.parseInt(list.get(0));
    	User user = query.loadUser(ssn);
    	return MessageEditor.makeRLoadUser(user);
    }
    
    private void updateUser(List<String> list){
    	int ssn = Integer.parseInt(list.get(0));
    	User user = UserMessageEditor.getUser(list.get(1));
    	query.updateUser(user, ssn);
    }
    
    private void deleteUser(List<String> list){
    	int ssn = Integer.parseInt(list.get(0));
    	query.deleteUser(ssn);
    }
    
    private String searchUser(List<String> list){
    	List<User> list2 = query.searchUserByName(list.get(0));
    	return MessageEditor.makeRSearchUser(list2);
    }
    
    private void addApp(List<String> list){
    	Appointment app = AppointmentMessageEditor.getAppointment(list.get(0));
    	query.addAppointment(app.getSSN(), app);
    }
    
    private void updateApp(List<String> list){
    	Appointment app = AppointmentMessageEditor.getAppointment(list.get(0));
    	query.updateAppointment(app.getSSN(), app);
    }
    
    private void deleteApp(List<String> list){
    	int ssn = Integer.parseInt(list.get(0));
    	Date date = Date.valueOf(list.get(1));
    	query.deleteAppointment(ssn, date);
    }
    
    private String searchAppDate(List<String> list){
    	Date date = Date.valueOf(list.get(0));
    	List<Appointment> list2 = query.searchUserAppointmentDateOnly(date);
    	return MessageEditor.makeRSearchAppSSN(list2);
    }
    
    private String searchAppSSN(List<String> list){
    	int ssn = Integer.parseInt(list.get(0));
    	List<Appointment> list2 = query.searchUserAppointments(ssn);
    	return MessageEditor.makeRSearchAppSSN(list2);
    }

}
